package com.icehelper.hades.base.log;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


public class TraceIdGenerator {
  private static final String[] PATCH_PATTERN = {"0", "00", "000", "0000", "00000", "000000", "0000000"};

  private static  AtomicInteger increase = new AtomicInteger(0);

  private static final int MAX_SELF_INCREMENT = 0xffffff;

  private static final String ipFactor = generatorIpFactor();

  private static final String pidFactor = generatorPidFactor();

  /**
   * 后缀标识
   * traceId要求为32位，30~31为后缀标识
   * nginx生成的id此两位固定为02，其他业务自选
   */
  private static final String suffixIdentify = "20";

  /**
   * 生成traceId
   * @return
   */
  public static String generatorTraceId(){
    StringBuffer buffer = new StringBuffer();
    buffer.append(ipFactor);
    buffer.append(generatorTimeFactor());
    buffer.append(pidFactor);
    buffer.append(generatorIncrementFactor());
    buffer.append(suffixIdentify);
    return buffer.toString();
  }

  /**
   * 生成IP因子
   * @return
   */
  private static String generatorIpFactor(){
    List<String> ips = getLocalIpList();
    String localIp = "127.0.0.1";
    if(ips.size() <= 0){
      return covertIp2Hex(localIp);
    }
    for (String ip:ips) {
      if(!localIp.equals(ip)){
        localIp = ip;
        break;
      }
    }
    return covertIp2Hex(localIp);
  }

  /**
   * 生成ID时间因子
   * @return
   */
  private static String generatorTimeFactor(){
    Long timeStamp = System.currentTimeMillis()/1000;
    return Long.toHexString(timeStamp);
  }

  /**
   * 当前进程因子
   * @return
   */
  private static String generatorPidFactor(){
    RuntimeMXBean rmx = ManagementFactory.getRuntimeMXBean();
    String name = rmx.getName();
    String pid = patch(Integer.toHexString(Integer.valueOf(name.substring(0,name.indexOf("@")))), 4);
    long startTime = rmx.getStartTime() % 1000;
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(startTime);
    String month = patch(Integer.toHexString(c.get(Calendar.MONTH)), 2);
    String day = patch(Integer.toHexString(c.get(Calendar.DAY_OF_MONTH)), 2);
    return month + day + pid;
  }

  /**
   * 生成自增因子
   * @return
   */
  private static String generatorIncrementFactor() {
    int result = increase.incrementAndGet();
    if(result > MAX_SELF_INCREMENT){
      increase.set(1);
      result = 1;
    }
    return patch(Integer.toHexString(result),6);
  }


  /**
   * 将IP地址转换成16进制字符串
   * @param ip ip地址
   * @return
   */
  private static String covertIp2Hex(String ip){
    String[] ipSegments = ip.split("\\.");
    StringBuffer buffer = new StringBuffer();
    Arrays.asList(ipSegments).stream().forEach(seg -> buffer.append(patch(Integer.toHexString(Integer.valueOf(seg)),2)));
    return buffer.toString();
  }

  /**
   * 字符串填充
   * @param hex 待填充值
   * @param length 填充长度
   * @return
   */
  private static String patch(String hex, int length) {
    if (hex.length() > length) {
      return hex.substring(0,4);
    }else if(hex.length() == length){
      return hex;
    }else {
      int gap = length - hex.length();
      return PATCH_PATTERN[(Math.min(gap, 7)) - 1] + hex;
    }
  }

  public static List<String> getLocalIpList(){
    List<String> ipList = new ArrayList<>();
    try {
      Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
      while (networkInterfaces.hasMoreElements()){
        NetworkInterface networkInterface = networkInterfaces.nextElement();
        Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
        while (inetAddresses.hasMoreElements()){
          InetAddress inetAddress = inetAddresses.nextElement();
          if(inetAddress instanceof Inet4Address){
            ipList.add(inetAddress.getHostAddress());
          }
        }
      }
    } catch (SocketException e) {
      e.printStackTrace();
    }
    return ipList;
  }

}
